﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using HPSocketCS;
using System.IO;

namespace FileUDClassLibrary
{
    /// <summary>
    /// 文件传输组件
    /// </summary>
    public partial class FileUpDownloadControl : UserControl
    {
        /// <summary>
        /// TCP组件
        /// </summary>
        private TcpPackClient aTcpClientObj = new TcpPackClient();

        /// <summary>
        /// 每次发送的最大字节数
        /// <para>取第一位用标识，所以数据最大发送4095，加上标识位就总共4096了</para>
        /// </summary>
        private int aMaxBufferLength = 4095;

        /// <summary>
        /// 当前正在使用的文件上传对象
        /// </summary>
        private FileUDInfoControl aCurrentFileUDObj = null;

        /// <summary>
        /// 当前正在发送的文件信息
        /// </summary>
        private SendFileInfo aCurrentSendFileInfo = new SendFileInfo();

        /// <summary>
        /// 发文件的状态
        /// </summary>
        private SendFileState aCurrentSendFileState = SendFileState.NoSend;

        /// <summary>
        /// 当前正在发送的文件路径
        /// </summary>
        private string aCurrentFilePath = "";

        private delegate void ConnectUpdateUiDelegate(int dataLength);
        /// <summary>
        /// 更新显示
        /// </summary>
        private ConnectUpdateUiDelegate UpdateUI;

        private delegate void UpdateMessage(string Message);
        /// <summary>
        /// 更新界面消息
        /// </summary>
        private UpdateMessage UpdataUIMessage;

        private delegate void UpDowloadedDelegate();
        /// <summary>
        /// 完成传输时，委托触发事件
        /// </summary>
        private UpDowloadedDelegate UpDowloadedEvent;

        public delegate void UpDowloaded();

        /// <summary>
        /// 服务器IP
        /// </summary>
        public string ServerIP
        {
            get { return aServerIP; }
            set
            {
                if (string.IsNullOrEmpty(value))
                    throw new Exception("IP地址不能为空");
                aServerIP = value;
            }
        }

        /// <summary>
        /// 服务器端口号
        /// </summary>
        public ushort ServerPort
        {
            get { return aServerPort; }
            set
            {
                if ((value <= 0) || (value > 65535))
                    throw new Exception("端口号不在可用范围");
                aServerPort = value;
            }
        }

        /// <summary>
        /// 服务器IP
        /// </summary>
        private string aServerIP = "";

        /// <summary>
        /// 服务器端口
        /// </summary>
        private ushort aServerPort = 0;

        /// <summary>
        /// 当全部文件对象传输完成时的事件
        /// </summary>
        public event C_EventClass.OnUpDowloadEventHandler OnUpDowload;

        /// <summary>
        /// 构造函数
        /// </summary>
        public FileUpDownloadControl()
        {
            InitializeComponent();
            Init();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            try
            {
                aTcpClientObj.OnConnect += OnConnect;
                aTcpClientObj.OnReceive += OnReceive;
                aTcpClientObj.OnClose += OnClose;
                UpdateUI = new ConnectUpdateUiDelegate(UpdateSendFileView);
                UpdataUIMessage = new UpdateMessage(UpdateMessageView);
                UpDowloadedEvent = new UpDowloadedDelegate(UpDowloadedOnEvent);
            }
            catch (Exception ex)
            {
            }
        }

        HandleResult OnConnect(TcpClient sender)
        {
            UpdateMessageView(string.Format("连接 {0} 成功", ServerIP));
            return HandleResult.Ok;
        }

        HandleResult OnReceive(TcpClient sender, byte[] bytes)
        {
            try
            {
                byte iOneByte = bytes[0];
                switch (iOneByte)
                {
                    case 1:
                        {
                            if (aCurrentSendFileState != SendFileState.Handshake) return HandleResult.Ignore;

                            aCurrentSendFileState = SendFileState.Sending;
                            if (!SendFileToServer_RFBP(aCurrentFilePath))
                            {
                                aCurrentFileUDObj.FileState = FileState.ERROR;
                                aCurrentSendFileState = SendFileState.NoSend;
                                aCurrentFilePath = "";
                                byte[] idatas = new byte[1];
                                idatas[0] = 4;
                                aTcpClientObj.Send(idatas, 1);
                                StartSendFile();
                            }
                            break;
                        }
                    case 3:
                        {
                            if (aCurrentSendFileState != SendFileState.Sending) return HandleResult.Ignore;

                            byte[] idatas = new byte[bytes.Length - 1];
                            Array.Copy(bytes, 1, idatas, 0, bytes.Length - 1);
                            string iFilePath = Encoding.Unicode.GetString(idatas);
                            UpdateMessageView(string.Format("发送 {0} 成功", aCurrentSendFileInfo.FileName));
                            aCurrentFileUDObj.FileState = FileState.FINISH;
                            aCurrentFileUDObj.ServerFilePath = iFilePath;
                            aCurrentSendFileState = SendFileState.NoSend;
                            aCurrentFilePath = "";
                            StartSendFile();
                            break;
                        }
                }

                return HandleResult.Ok;
            }
            catch (Exception Err)
            {
                return HandleResult.Ignore;
            }
        }

        HandleResult OnClose(TcpClient sender, SocketOperation enOperation, int errorCode)
        {
            if(aCurrentFileUDObj!=null)
            {
                aCurrentFileUDObj.FileState = FileState.ERROR;
            }
            aCurrentSendFileState = SendFileState.NoSend;
            aCurrentFilePath = "";
            UpdateMessageView("连接断开");
            return HandleResult.Ok;
        }

        /// <summary>
        /// 开始发送文件
        /// </summary>
        public void StartSendFile()
        {
            bool iIsHaveNeedSend = false;
            foreach (FileUDInfoControl iFileUDObj in FLPan_FileUDInfos.Controls)
            {
                if (iFileUDObj.FileState == FileState.WAIT)
                {
                    iIsHaveNeedSend = true;
                    aCurrentFileUDObj = iFileUDObj;
                    aCurrentFileUDObj.FileState = FileState.UPING;
                    FileInfo iFileInfo = new FileInfo(aCurrentFileUDObj.FilePath);
                    aCurrentSendFileInfo = new SendFileInfo();
                    aCurrentSendFileInfo.FileName = iFileInfo.Name;
                    aCurrentSendFileInfo.FileSize = iFileInfo.Length;
                    aCurrentFilePath = aCurrentFileUDObj.FilePath;

                    aCurrentSendFileState = SendFileState.Handshake;
                    byte[] iObjBytes = aTcpClientObj.StructureToByte(aCurrentSendFileInfo);
                    byte[] iSendBytes = new byte[iObjBytes.Length + 1];
                    iSendBytes[0] = 1;
                    Array.Copy(iObjBytes, 0, iSendBytes, 1, iObjBytes.Length);

                    aTcpClientObj.Send(iSendBytes, iSendBytes.Length);
                    UpdateMessageView(string.Format("正在发送 {0} ……", aCurrentSendFileInfo.FileName));
                    return;
                }
            }

            if (!iIsHaveNeedSend)
            {
                UpdateMessageView("全部文件发送完毕 ……");
                UpDowloadedOnEvent();
            }
        }

        /// <summary>
        /// 读取并发送文件数据
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        /// <returns></returns>
        private bool SendFileToServer_RFBP(string FilePath)
        {
            if (!File.Exists(FilePath)) return false;
            FileStream iFileObj = new FileStream(FilePath, FileMode.Open, FileAccess.Read);
            long iFileSize = iFileObj.Length;
            if (iFileSize == 0) return false;

            if (iFileSize < aMaxBufferLength)
            {
                byte[] idatas = new byte[iFileSize + 1];
                idatas[0] = 2;
                iFileObj.Read(idatas, 1, (int)iFileSize);
                if (aTcpClientObj.Send(idatas, idatas.Length))
                    UpdateSendFileView((int)iFileSize);
            }
            else
            {
                long iLeftLength = iFileSize;
                int iReadLength = 0;
                byte[] idatas;
                while (iLeftLength != 0)
                {

                    if (iLeftLength < aMaxBufferLength)
                    {
                        idatas = new byte[iLeftLength + 1];
                        iReadLength = iFileObj.Read(idatas, 1, (int)iLeftLength);
                    }
                    else
                    {
                        idatas = new byte[aMaxBufferLength + 1];
                        iReadLength = iFileObj.Read(idatas, 1, aMaxBufferLength);
                    }
                    idatas[0] = 2;
                    if (aTcpClientObj.Send(idatas, idatas.Length))
                        UpdateSendFileView(iReadLength);
                    iLeftLength -= iReadLength;
                }
            }

            return true;
        }

        /// <summary>
        /// 更新进度信息
        /// </summary>
        /// <param name="datalength"></param>
        private void UpdateSendFileView(int datalength)
        {
            if (aCurrentFileUDObj == null) return;
            if (aCurrentSendFileState != SendFileState.Sending) return;
            if (aCurrentFileUDObj.InvokeRequired)
            {
                aCurrentFileUDObj.Invoke(UpdateUI, datalength);
            }
            else
            {
                aCurrentFileUDObj.Value += datalength;
            }
        }

        /// <summary>
        /// 更新消息
        /// </summary>
        /// <param name="Message"></param>
        private void UpdateMessageView(string Message)
        {
            if(lab_msg.InvokeRequired)
            {
                lab_msg.Invoke(UpdataUIMessage, Message);
            }
            else
            {
                lab_msg.Text = Message;
            }
        }

        /// <summary>
        /// 触发事件
        /// </summary>
        private void UpDowloadedOnEvent()
        {
            if(InvokeRequired)
            {
                Invoke(UpDowloadedEvent);
            }
            else
            {
                if (OnUpDowload != null)
                {
                    Dictionary<string, string> iFilePaths = new Dictionary<string, string>();
                    List<string> iErrFiles = new List<string>();
                    foreach (FileUDInfoControl iFileUDObj in FLPan_FileUDInfos.Controls)
                    {
                        if (iFileUDObj.FileState == FileState.ERROR)
                            iErrFiles.Add(iFileUDObj.FileName);
                        else if (iFileUDObj.FileState == FileState.FINISH)
                            iFilePaths[iFileUDObj.FileName] = iFileUDObj.ServerFilePath;
                    }
                    OnUpDowload(iFilePaths, iErrFiles);
                }
            }
        }

        /// <summary>
        /// 新增一个文件信息
        /// </summary>
        /// <param name="FilePath">文件路径</param>
        public void AddFileUDInfo(string FilePath)
        {
            FileInfo iFileInfoObj = new FileInfo(FilePath);
            FileUDInfoControl iFileUDObj = new FileUDInfoControl();
            iFileUDObj.FilePath = FilePath;
            iFileUDObj.FileSize = iFileInfoObj.Length;

            FLPan_FileUDInfos.Controls.Add(iFileUDObj);
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <returns></returns>
        public bool Connect()
        {
            if (aTcpClientObj.State == ServiceState.Started) return true;
            try
            {
                if (aTcpClientObj.Connect(aServerIP, aServerPort, false))
                    return true;
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <returns></returns>
        public bool Stop()
        {
            if (aTcpClientObj.State == ServiceState.Stoped) return true;
            try
            {
                if (aTcpClientObj.Stop())
                    return true;
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 检查是否已经连接服务器
        /// </summary>
        /// <returns></returns>
        public bool GetIsConnect()
        {
            if (aTcpClientObj.State == ServiceState.Started) return true;
            else return false;
        }

        /// <summary>
        /// 检查是否有需要发送的文件
        /// </summary>
        /// <returns></returns>
        public bool GetIsHaveNeedSend()
        {
            bool iret = false;
            foreach (FileUDInfoControl iObj in FLPan_FileUDInfos.Controls)
            {
                if (iObj.FileState == FileState.WAIT)
                {
                    iret = true;
                    break;
                }
            }
            return iret;
        }
    }
}
